#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import csv
import time
import socket
import urllib.parse
import threading
import sys
import subprocess
from http.server import HTTPServer, BaseHTTPRequestHandler
from html import escape
import json

class TableSystem:
    def __init__(self, base_path="db"):
        self.base_path = base_path
        self.databases = {}
        self.dirty_data = {}
        self.lock = threading.RLock()
        self.last_sync = time.time()
        self.load_all_databases()
    
    def load_all_databases(self):
        if not os.path.exists(self.base_path):
            os.makedirs(self.base_path)
        
        items = [item for item in os.listdir(self.base_path) 
                if os.path.isdir(os.path.join(self.base_path, item))]
        
        if not items:
            self.create_demo_database()
        else:
            for item in items:
                self.load_database(item)
    
    def create_demo_database(self):
        db_name = "demo"
        db_path = os.path.join(self.base_path, db_name)
        
        # 演示数据包含换行符的示例
        demo_data = [
            ["工号", "姓名", "部门", "职位", "工资", "备注"],
            ["001", "张三", "技术部", "工程师", "8000", "优秀员工\n技术骨干"],
            ["002", "李四", "销售部", "销售经理", "7500", "业绩突出\n团队领导"],
            ["003", "王五", "市场部", "市场专员", "6000", "创意丰富\n沟通能力强"],
            ["004", "赵六", "人事部", "HR专员", "5500", "细心负责\n员工关系处理"]
        ]
        
        demo_users = [
            ["admin", "1234"],
            ["manager", "1111"],
            ["user", "2222"]
        ]
        
        demo_view = [
            ["*", "*", "*", "*", "*", "*"],
            ["*", "*", "*", "*", "admin,manager", "*"],
            ["*", "*", "*", "*", "admin,manager", "*"],
            ["*", "*", "*", "*", "admin,manager", "*"],
            ["*", "*", "*", "*", "admin,manager", "*"]
        ]
        
        demo_edit = [
            ["admin", "admin", "admin", "admin", "admin", "admin"],
            ["admin", "admin,manager", "admin,manager", "admin,manager", "admin", "admin,manager"],
            ["admin", "admin,manager", "admin,manager", "admin,manager", "admin", "admin,manager"],
            ["admin", "admin,manager", "admin,manager", "admin,manager", "admin", "admin,manager"],
            ["admin", "admin,manager", "admin,manager", "admin,manager", "admin", "admin,manager"]
        ]
        
        os.makedirs(db_path, exist_ok=True)
        
        # 新创建的演示数据库使用UTF-8编码
        self.write_csv_with_encoding(os.path.join(db_path, "data.csv"), demo_data, 'utf-8')
        self.write_csv_with_encoding(os.path.join(db_path, "user.csv"), demo_users, 'utf-8')
        self.write_csv_with_encoding(os.path.join(db_path, "view.csv"), demo_view, 'utf-8')
        self.write_csv_with_encoding(os.path.join(db_path, "edit.csv"), demo_edit, 'utf-8')
        self.write_csv_with_encoding(os.path.join(db_path, "log.csv"), [["时间", "用户", "操作", "详情"]], 'utf-8')
        
        print("已创建演示数据库: {}".format(db_name))
        self.load_database(db_name)
    
    def load_database(self, db_name):
        db_path = os.path.join(self.base_path, db_name)
        
        try:
            data_file = os.path.join(db_path, "data.csv")
            user_file = os.path.join(db_path, "user.csv")
            view_file = os.path.join(db_path, "view.csv")
            edit_file = os.path.join(db_path, "edit.csv")
            
            # 检测文件编码并记录
            data_encoding = self.detect_file_encoding(data_file)
            user_encoding = self.detect_file_encoding(user_file)
            view_encoding = self.detect_file_encoding(view_file)
            edit_encoding = self.detect_file_encoding(edit_file)
            
            # 使用检测到的编码读取文件
            data = self.read_csv_with_encoding(data_file, data_encoding)
            users = self.read_csv_with_encoding(user_file, user_encoding)
            view = self.read_csv_with_encoding(view_file, view_encoding)
            edit = self.read_csv_with_encoding(edit_file, edit_encoding)
            
            # 记录每个文件的编码
            self.databases[db_name] = {
                'data': data,
                'users': users,
                'view': view,
                'edit': edit,
                'log_file': os.path.join(db_path, "log.csv"),
                'encodings': {
                    'data': data_encoding,
                    'users': user_encoding,
                    'view': view_encoding,
                    'edit': edit_encoding,
                    'log': self.detect_file_encoding(os.path.join(db_path, "log.csv"))
                }
            }
            
        except Exception as e:
            print("加载数据库 {} 失败: {}".format(db_name, e))
    
    def detect_file_encoding(self, filepath):
        """检测文件编码 - 使用标准库方法"""
        if not os.path.exists(filepath):
            return 'utf-8'  # 新文件默认使用UTF-8
        
        # 尝试常见编码
        encodings = ['utf-8', 'gbk', 'gb2312', 'gb18030', 'latin1']
        
        for encoding in encodings:
            try:
                with open(filepath, 'r', encoding=encoding) as f:
                    # 读取前几行来验证编码
                    for i, line in enumerate(f):
                        if i > 5:  # 只检查前几行
                            break
                    return encoding
            except (UnicodeDecodeError, UnicodeError):
                continue
        
        # 如果都不行，默认使用utf-8
        return 'utf-8'
    
    def read_csv_with_encoding(self, filepath, encoding=None):
        """使用指定编码读取CSV"""
        if not os.path.exists(filepath):
            return []
        
        if encoding is None:
            encoding = self.detect_file_encoding(filepath)
            
        try:
            with open(filepath, 'r', encoding=encoding, errors='ignore') as f:
                return list(csv.reader(f))
        except Exception as e:
            print("读取文件 {} 失败 (编码: {}): {}".format(filepath, encoding, e))
            # 尝试用utf-8和gbk再次读取
            for encoding in ['utf-8', 'gbk']:
                try:
                    with open(filepath, 'r', encoding=encoding, errors='ignore') as f:
                        return list(csv.reader(f))
                except:
                    continue
            return []
    
    def write_csv_with_encoding(self, filepath, data, encoding=None):
        """使用指定编码写入CSV"""
        try:
            os.makedirs(os.path.dirname(filepath), exist_ok=True)
            
            # 如果没有指定编码，尝试从数据库记录中获取
            if encoding is None:
                for db_name, db_info in self.databases.items():
                    if filepath.startswith(os.path.join(self.base_path, db_name)):
                        # 根据文件名确定数据类型
                        data_type = os.path.basename(filepath).replace('.csv', '')
                        if data_type in db_info.get('encodings', {}):
                            encoding = db_info['encodings'][data_type]
                        break
            
            # 如果还是没有编码，使用UTF-8
            if encoding is None:
                encoding = 'utf-8'
                
            with open(filepath, 'w', encoding=encoding, errors='ignore', newline='') as f:
                writer = csv.writer(f)
                writer.writerows(data)
        except Exception as e:
            print("写入文件 {} 失败: {}".format(filepath, e))
    
    def mark_dirty(self, db_name, data_type):
        with self.lock:
            if db_name not in self.dirty_data:
                self.dirty_data[db_name] = {}
            self.dirty_data[db_name][data_type] = True
    
    def sync_dirty_data(self):
        current_time = time.time()
        if current_time - self.last_sync < 10:
            return
        
        with self.lock:
            if not self.dirty_data:
                self.last_sync = current_time
                return
            
            dirty_copy = self.dirty_data.copy()
            self.dirty_data.clear()
            
            for db_name, dirty_types in dirty_copy.items():
                if db_name not in self.databases:
                    continue
                
                db = self.databases[db_name]
                for data_type in dirty_types:
                    if data_type == 'log':
                        continue
                    file_path = os.path.join(self.base_path, db_name, "{}.csv".format(data_type))
                    # 使用数据库记录的编码写入
                    encoding = db.get('encodings', {}).get(data_type, 'utf-8')
                    self.write_csv_with_encoding(file_path, db[data_type], encoding)
                    print("已同步 {} 的 {} 数据 (编码: {})".format(db_name, data_type, encoding))
            
            self.last_sync = current_time
    
    def force_sync_all(self):
        with self.lock:
            for db_name, db in self.databases.items():
                for data_type in ['data', 'users', 'view', 'edit']:
                    file_path = os.path.join(self.base_path, db_name, "{}.csv".format(data_type))
                    # 使用数据库记录的编码写入
                    encoding = db.get('encodings', {}).get(data_type, 'utf-8')
                    self.write_csv_with_encoding(file_path, db[data_type], encoding)
            print("已同步所有数据")
    
    def authenticate_user(self, db_name, username, password):
        if db_name not in self.databases:
            return False
        
        users = self.databases[db_name]['users']
        for user_row in users:
            if len(user_row) >= 2 and user_row[0] == username and user_row[1] == password:
                return True
        return False
    
    def change_password(self, db_name, username, old_password, new_password):
        if db_name not in self.databases:
            return False
        
        with self.lock:
            users = self.databases[db_name]['users']
            for i, user_row in enumerate(users):
                if len(user_row) >= 2 and user_row[0] == username and user_row[1] == old_password:
                    users[i][1] = new_password
                    self.mark_dirty(db_name, 'users')
                    self.log_operation(db_name, username, "修改密码", "密码已更新")
                    return True
        return False
    
    def check_permission(self, db_name, username, row_idx, col_idx, permission_type='view'):
        if db_name not in self.databases:
            return False
        
        db = self.databases[db_name]
        perm_data = db[permission_type]
        
        if row_idx >= len(perm_data) or col_idx >= len(perm_data[row_idx]):
            return False
        
        cell_perm = perm_data[row_idx][col_idx]
        return cell_perm == "*" or username in cell_perm.split(',')
    
    def get_cell_display_value(self, db_name, username, row_idx, col_idx):
        if not self.check_permission(db_name, username, row_idx, col_idx, 'view'):
            return "***"
        
        db = self.databases[db_name]
        if row_idx < len(db['data']) and col_idx < len(db['data'][row_idx]):
            return db['data'][row_idx][col_idx]
        return ""
    
    def update_cell(self, db_name, username, row_idx, col_idx, new_value):
        if not self.check_permission(db_name, username, row_idx, col_idx, 'edit'):
            return False
        
        with self.lock:
            db = self.databases[db_name]
            if row_idx < len(db['data']) and col_idx < len(db['data'][row_idx]):
                old_value = db['data'][row_idx][col_idx]
                db['data'][row_idx][col_idx] = new_value
                self.mark_dirty(db_name, 'data')
                self.log_operation(db_name, username, "更新单元格", 
                                 "行{}列{}: {} -> {}".format(row_idx, col_idx, old_value, new_value))
                return True
        return False
    
    def log_operation(self, db_name, username, operation, details):
        if db_name not in self.databases:
            return
        
        log_entry = [time.strftime("%Y-%m-%d %H:%M:%S"), username, operation, details]
        log_file = self.databases[db_name]['log_file']
        log_encoding = self.databases[db_name]['encodings'].get('log', 'utf-8')
        
        logs = self.read_csv_with_encoding(log_file, log_encoding)
        logs.append(log_entry)
        self.write_csv_with_encoding(log_file, logs, log_encoding)


class TableRequestHandler(BaseHTTPRequestHandler):
    def __init__(self, *args, **kwargs):
        self.system = kwargs.pop('system')
        super().__init__(*args, **kwargs)
    
    def do_GET(self):
        try:
            self.system.sync_dirty_data()
            parsed_path = urllib.parse.urlparse(self.path)
            query_params = urllib.parse.parse_qs(parsed_path.query)
            
            if parsed_path.path == '/':
                self.handle_main_page(query_params)
            elif parsed_path.path == '/restart':
                self.handle_restart(query_params)
            elif parsed_path.path == '/changepassword':
                self.handle_change_password_page(query_params)
            elif parsed_path.path == '/sync':
                self.handle_sync()
            elif parsed_path.path.startswith('/static/'):
                self.handle_static_file(parsed_path.path)
            else:
                self.send_response(404)
                self.end_headers()
                
        except Exception as e:
            print("GET请求处理错误: {}".format(e))
            self.send_response(500)
            self.end_headers()
    
    def do_POST(self):
        try:
            content_length = int(self.headers['Content-Length'])
            post_data = self.rfile.read(content_length).decode('utf-8')
            post_params = urllib.parse.parse_qs(post_data)
            
            parsed_path = urllib.parse.urlparse(self.path)
            
            if parsed_path.path == '/update':
                self.handle_update(post_params)
            elif parsed_path.path == '/changepassword':
                self.handle_change_password(post_params)
            else:
                self.send_response(404)
                self.end_headers()
                
        except Exception as e:
            print("POST请求处理错误: {}".format(e))
            self.send_response(500)
            self.end_headers()
    
    def handle_main_page(self, query_params):
        db_name = query_params.get('db', [None])[0]
        username = query_params.get('user', [None])[0]
        password = query_params.get('key', [None])[0]
        
        if not all([db_name, username, password]):
            self.show_login_page()
            return
        
        # URL解码中文参数
        try:
            db_name = urllib.parse.unquote(db_name)
            username = urllib.parse.unquote(username)
            password = urllib.parse.unquote(password)
        except:
            pass
        
        if not self.system.authenticate_user(db_name, username, password):
            self.show_login_page("认证失败")
            return
        
        self.show_table_page(db_name, username, password)
    
    def handle_restart(self, query_params):
        db_name = query_params.get('db', [None])[0]
        username = query_params.get('user', [None])[0]
        password = query_params.get('key', [None])[0]
        
        # URL解码中文参数
        try:
            db_name = urllib.parse.unquote(db_name)
            username = urllib.parse.unquote(username)
            password = urllib.parse.unquote(password)
        except:
            pass
        
        if username != 'admin':
            self.send_response(403)
            self.end_headers()
            return
        
        if query_params.get('confirm', [None])[0] == 'true':
            self.perform_restart(db_name, username)
            return
        
        self.show_restart_page(db_name, username, password)
    
    def handle_sync(self):
        self.system.force_sync_all()
        self.send_response(200)
        self.send_header('Content-type', 'text/plain; charset=utf-8')
        self.end_headers()
        self.wfile.write("数据已同步".encode('utf-8'))
    
    def handle_change_password_page(self, query_params):
        db_name = query_params.get('db', [None])[0]
        username = query_params.get('user', [None])[0]
        password = query_params.get('key', [None])[0]
        
        if not all([db_name, username, password]):
            self.show_login_page()
            return
        
        # URL解码中文参数
        try:
            db_name = urllib.parse.unquote(db_name)
            username = urllib.parse.unquote(username)
            password = urllib.parse.unquote(password)
        except:
            pass
        
        if not self.system.authenticate_user(db_name, username, password):
            self.show_login_page("认证失败")
            return
        
        self.show_change_password_page(db_name, username, password)
    
    def handle_static_file(self, path):
        static_dir = "static"
        # 解码URL路径，支持中文文件名
        filename = urllib.parse.unquote(path[8:])
        
        # 安全检查：防止目录遍历攻击
        if '..' in filename or filename.startswith('/'):
            self.send_response(403)
            self.end_headers()
            return
        
        file_path = os.path.join(static_dir, filename)
        if not os.path.exists(file_path):
            self.send_response(404)
            self.end_headers()
            return
        
        # 确定文件类型
        ext = os.path.splitext(filename)[1].lower()
        if ext in ['.html', '.htm']:
            content_type = 'text/html; charset=utf-8'
        elif ext == '.css':
            content_type = 'text/css; charset=utf-8'
        elif ext == '.js':
            content_type = 'application/javascript; charset=utf-8'
        else:
            content_type = 'text/plain; charset=utf-8'
        
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
        except:
            try:
                with open(file_path, 'r', encoding='gbk') as f:
                    content = f.read()
            except:
                self.send_response(500)
                self.end_headers()
                return
        
        self.send_response(200)
        self.send_header('Content-type', content_type)
        self.end_headers()
        self.wfile.write(content.encode('utf-8'))
    
    def handle_change_password(self, post_params):
        db_name = post_params.get('db', [None])[0]
        username = post_params.get('user', [None])[0]
        old_password = post_params.get('old_password', [''])[0]
        new_password = post_params.get('new_password', [''])[0]
        confirm_password = post_params.get('confirm_password', [''])[0]
        
        if not self.system.authenticate_user(db_name, username, old_password):
            self.send_response(401)
            self.end_headers()
            return
        
        if new_password != confirm_password:
            self.send_response(400)
            self.end_headers()
            return
        
        if self.system.change_password(db_name, username, old_password, new_password):
            response = {'success': True, 'message': '密码修改成功'}
        else:
            response = {'success': False, 'message': '密码修改失败'}
        
        self.send_response(200)
        self.send_header('Content-type', 'application/json; charset=utf-8')
        self.end_headers()
        self.wfile.write(json.dumps(response, ensure_ascii=False).encode('utf-8'))
    
    def handle_update(self, post_params):
        db_name = post_params.get('db', [None])[0]
        username = post_params.get('user', [None])[0]
        password = post_params.get('key', [None])[0]
        row_idx = int(post_params.get('row', [0])[0])
        col_idx = int(post_params.get('col', [0])[0])
        new_value = post_params.get('value', [''])[0]
        
        if not self.system.authenticate_user(db_name, username, password):
            self.send_response(401)
            self.end_headers()
            return
        
        if self.system.update_cell(db_name, username, row_idx, col_idx, new_value):
            response = {'success': True, 'message': '更新成功'}
        else:
            response = {'success': False, 'message': '更新失败'}
        
        self.send_response(200)
        self.send_header('Content-type', 'application/json; charset=utf-8')
        self.end_headers()
        self.wfile.write(json.dumps(response, ensure_ascii=False).encode('utf-8'))
    
    def show_login_page(self, error_message=None):
        available_dbs = list(self.system.databases.keys())
        db_options = "".join('<option value="{}">{}</option>'.format(urllib.parse.quote(db), db) for db in available_dbs)
        db_list = ', '.join(available_dbs) if available_dbs else '无'
        
        html = """<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>共享填表系统</title>
<style>
body {{ font-family: Arial; margin: 40px; background: #f5f5f5; }}
.container {{ max-width: 400px; margin: 0 auto; background: white; padding: 30px; border-radius: 5px; }}
h1 {{ text-align: center; color: #333; }}
.form-group {{ margin-bottom: 20px; }}
label {{ display: block; margin-bottom: 5px; }}
select, input {{ width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 3px; box-sizing: border-box; }}
.btn {{ background: #4CAF50; color: white; padding: 10px; border: none; border-radius: 3px; cursor: pointer; width: 100%; }}
.error {{ color: red; text-align: center; margin-bottom: 15px; }}
.info {{ font-size: 12px; color: #666; margin-top: 5px; }}
</style>
</head>
<body>
<div class="container">
<h1>共享填表系统</h1>
{error_html}
<form method="GET" action="/">
<div class="form-group">
<label>数据库:</label>
<select name="db" required><option value="">请选择</option>{db_options}</select>
<div class="info">可用: {db_list}</div>
</div>
<div class="form-group">
<label>用户名:</label>
<input type="text" name="user" required>
</div>
<div class="form-group">
<label>密码:</label>
<input type="password" name="key" required>
</div>
<button type="submit" class="btn">登录</button>
</form>
<div style="text-align:center; margin-top:15px; font-size:12px; color:#666;">
<a href="/static/help.html" target="_blank">使用帮助</a>
</div>
</div>
</body>
</html>""".format(
            error_html='<div class="error">{}</div>'.format(escape(error_message)) if error_message else '',
            db_options=db_options,
            db_list=db_list
        )
        
        self.send_response(200)
        self.send_header('Content-type', 'text/html; charset=utf-8')
        self.end_headers()
        self.wfile.write(html.encode('utf-8'))
    
    def show_table_page(self, db_name, username, password):
        db = self.system.databases[db_name]
        data = db['data']
        
        # URL编码参数，确保中文正确传递
        encoded_db = urllib.parse.quote(db_name)
        encoded_user = urllib.parse.quote(username)
        encoded_key = urllib.parse.quote(password)
        
        table_html = '<table border="1" cellspacing="0" cellpadding="8" style="width:100%; border-collapse:collapse; table-layout:fixed;">'
        table_html += '<tr style="background:#e0e0e0;">'
        for header in data[0]:
            table_html += '<th style="word-wrap:break-word; max-width:300px; min-width:80px;">{}</th>'.format(escape(header))
        table_html += '</tr>'
        
        for row_idx, row in enumerate(data[1:], 1):
            table_html += '<tr>'
            for col_idx, cell in enumerate(row):
                display_value = self.system.get_cell_display_value(db_name, username, row_idx, col_idx)
                can_edit = self.system.check_permission(db_name, username, row_idx, col_idx, 'edit')
                
                cell_style = "word-wrap:break-word; max-width:300px; min-width:80px; white-space: pre-wrap; "
                if can_edit and display_value != "***":
                    bg_color = "#e6f3ff"
                    cell_style += "background:{}".format(bg_color)
                    # 使用innerHTML来保留换行符，而不是textContent
                    table_html += '<td style="{}" ondblclick="startEdit({}, {})"><span id="display_{}_{}">{}</span></td>'.format(
                        cell_style, row_idx, col_idx, row_idx, col_idx, escape(display_value).replace('\n', '<br>'))
                else:
                    bg_color = "#f9f9f9" if display_value == "***" else "white"
                    cell_style += "background:{}".format(bg_color)
                    table_html += '<td style="{}">{}</td>'.format(cell_style, escape(display_value).replace('\n', '<br>'))
            table_html += '</tr>'
        
        table_html += '</table>'
        
        restart_btn = ''
        if username == 'admin':
            restart_btn = '<a href="/restart?db={}&user={}&key={}" style="background:#ff9800;">重启系统</a>'.format(encoded_db, encoded_user, encoded_key)
        
        html = """<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{db_name} - 共享填表系统</title>
<style>
body {{ font-family: Arial; margin: 0; background: #f5f5f5; }}
.header {{ background: #333; color: white; padding: 15px 20px; }}
.header h1 {{ margin: 0; display: inline; }}
.user-info {{ float: right; }}
.container {{ padding: 20px; }}
.controls {{ margin-bottom: 15px; }}
a {{ background: #4CAF50; color: white; padding: 8px 15px; text-decoration: none; border-radius: 3px; margin-left: 5px; }}
.edit-modal {{ display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); }}
.edit-content {{ position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); background: white; padding: 20px; border-radius: 5px; width: 500px; max-width: 90%; }}
table {{ table-layout: fixed; width: 100%; }}
td, th {{ word-wrap: break-word; max-width: 300px; min-width: 80px; white-space: pre-wrap; }}
</style>
<script>
var currentRow = 0;
var currentCol = 0;
var currentDb = '{encoded_db}';
var currentUser = '{encoded_user}';
var currentKey = '{encoded_key}';

function startEdit(row, col) {{
    currentRow = row;
    currentCol = col;
    var displayElem = document.getElementById('display_' + row + '_' + col);
    // 获取原始文本内容（去掉HTML标签）
    var textContent = displayElem.textContent || displayElem.innerText;
    document.getElementById('editValue').value = textContent;
    document.getElementById('editModal').style.display = 'block';
    document.getElementById('editValue').focus();
}}

function saveEdit() {{
    var newValue = document.getElementById('editValue').value;
    fetch('/update', {{
        method: 'POST',
        headers: {{'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'}},
        body: 'db=' + currentDb + '&user=' + currentUser + '&key=' + currentKey + 
              '&row=' + currentRow + '&col=' + currentCol + '&value=' + encodeURIComponent(newValue)
    }})
    .then(function(response) {{ return response.json(); }})
    .then(function(data) {{
        if (data.success) {{
            // 更新显示内容，将换行符转换为<br>
            var displayHtml = newValue.replace(/\\n/g, '<br>');
            document.getElementById('display_' + currentRow + '_' + currentCol).innerHTML = displayHtml;
            alert('更新成功');
        }} else {{
            alert('更新失败: ' + data.message);
        }}
        document.getElementById('editModal').style.display = 'none';
    }})
    .catch(function(error) {{
        alert('网络错误: ' + error);
        document.getElementById('editModal').style.display = 'none';
    }});
}}

function cancelEdit() {{
    document.getElementById('editModal').style.display = 'none';
}}

// ESC键关闭编辑框
document.addEventListener('keydown', function(event) {{
    if (event.key === 'Escape') {{
        cancelEdit();
    }}
}});

// 点击模态框外部关闭编辑框
document.addEventListener('click', function(event) {{
    var modal = document.getElementById('editModal');
    if (event.target === modal) {{
        cancelEdit();
    }}
}});
</script>
</head>
<body>
<div class="header">
<h1>{db_name} - 共享填表系统</h1>
<div class="user-info">
用户: {username} | 
{restart_button}
<a href="/changepassword?db={encoded_db}&user={encoded_user}&key={encoded_key}">修改密码</a>
<a href="/static/help.html" target="_blank">帮助</a>
<a href="/">退出</a>
</div>
</div>
<div class="container">
{table_html}
</div>

<div id="editModal" class="edit-modal">
<div class="edit-content">
<h3>编辑单元格</h3>
<textarea id="editValue" rows="6" style="width: 100%; padding: 8px; box-sizing: border-box; font-family: Arial; font-size: 14px;"></textarea>
<div style="margin-top: 15px; text-align: right;">
<button onclick="saveEdit()" style="background: #4CAF50; color: white; border: none; padding: 8px 15px; border-radius: 3px; cursor: pointer;">保存</button>
<button onclick="cancelEdit()" style="background: #6c757d; color: white; border: none; padding: 8px 15px; border-radius: 3px; cursor: pointer; margin-left: 10px;">取消</button>
</div>
</div>
</div>
</body>
</html>""".format(
            db_name=db_name,
            username=username,
            restart_button=restart_btn,
            encoded_db=encoded_db,
            encoded_user=encoded_user,
            encoded_key=encoded_key,
            table_html=table_html
        )
        
        self.send_response(200)
        self.send_header('Content-type', 'text/html; charset=utf-8')
        self.end_headers()
        self.wfile.write(html.encode('utf-8'))
    
    def show_restart_page(self, db_name, username, password):
        encoded_db = urllib.parse.quote(db_name)
        encoded_user = urllib.parse.quote(username)
        encoded_key = urllib.parse.quote(password)
        
        html = """<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>重启系统</title>
<style>
body {{ font-family: Arial; margin: 40px; background: #f5f5f5; }}
.container {{ max-width: 500px; margin: 0 auto; background: white; padding: 30px; border-radius: 5px; text-align: center; }}
h1 {{ color: #333; }}
.warning {{ background: #fff3cd; border: 1px solid #ffeaa7; padding: 15px; margin: 20px 0; border-radius: 5px; }}
.btn {{ background: #ff9800; color: white; padding: 10px 20px; border: none; border-radius: 3px; cursor: pointer; text-decoration: none; margin: 0 10px; }}
.btn-cancel {{ background: #6c757d; }}
</style>
<script>
function performRestart() {{
    document.getElementById('restartMessage').style.display = 'block';
    document.getElementById('restartButton').style.display = 'none';
    setTimeout(function() {{
        window.location.href = '/?db={encoded_db}&user={encoded_user}&key={encoded_key}';
    }}, 5000);
    fetch('/restart?db={encoded_db}&user={encoded_user}&key={encoded_key}&confirm=true').catch(function() {{}});
}}
</script>
</head>
<body>
<div class="container">
<h1>重启系统</h1>
<div class="warning">
<strong>警告：</strong>这将完全重启服务器进程。<br>
重启过程大约需要3-5秒，重启后页面将自动刷新。
</div>
<p>确定要重启系统吗？</p>
<div>
<button id="restartButton" class="btn" onclick="performRestart()">确认重启</button>
<a href="/?db={encoded_db}&user={encoded_user}&key={encoded_key}" class="btn btn-cancel">取消</a>
</div>
<div id="restartMessage" style="display: none; margin-top: 20px; color: #ff9800;">
<p>系统正在重启，请稍候...</p>
</div>
</div>
</body>
</html>""".format(
            encoded_db=encoded_db,
            encoded_user=encoded_user,
            encoded_key=encoded_key
        )
        
        self.send_response(200)
        self.send_header('Content-type', 'text/html; charset=utf-8')
        self.end_headers()
        self.wfile.write(html.encode('utf-8'))
    
    def perform_restart(self, db_name, username):
        self.system.log_operation(db_name, username, "重启系统", "服务器进程重启")
        
        self.send_response(200)
        self.send_header('Content-type', 'text/html; charset=utf-8')
        self.end_headers()
        self.wfile.write("重启中...".encode('utf-8'))
        
        self.system.force_sync_all()
        
        # 彻底重启：启动新进程后立即退出当前进程
        python = sys.executable
        script = os.path.abspath(sys.argv[0])
        args = sys.argv[1:]
        
        # 确保新进程在独立的环境中启动
        env = os.environ.copy()
        
        if os.name == 'nt':  # Windows
            subprocess.Popen([python, script] + args, env=env, close_fds=True)
        else:  # Linux/Unix
            # 使用execv替换当前进程，或者使用Popen启动新进程后退出
            subprocess.Popen([python, script] + args, env=env, close_fds=True)
        
        # 立即退出当前进程
        os._exit(0)
    
    def show_change_password_page(self, db_name, username, password):
        encoded_db = urllib.parse.quote(db_name)
        encoded_user = urllib.parse.quote(username)
        encoded_key = urllib.parse.quote(password)
        
        html = """<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>修改密码</title>
<style>
body {{ font-family: Arial; margin: 40px; background: #f5f5f5; }}
.container {{ max-width: 400px; margin: 0 auto; background: white; padding: 30px; border-radius: 5px; }}
h1 {{ text-align: center; color: #333; }}
.form-group {{ margin-bottom: 20px; }}
label {{ display: block; margin-bottom: 5px; }}
input {{ width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 3px; box-sizing: border-box; }}
.btn {{ background: #4CAF50; color: white; padding: 10px; border: none; border-radius: 3px; cursor: pointer; width: 100%; }}
</style>
<script>
function changePassword() {{
    var oldPass = document.getElementById('old_password').value;
    var newPass = document.getElementById('new_password').value;
    var confirmPass = document.getElementById('confirm_password').value;
    
    if (newPass !== confirmPass) {{
        alert('新密码和确认密码不匹配');
        return;
    }}
    
    fetch('/changepassword', {{
        method: 'POST',
        headers: {{'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'}},
        body: 'db={encoded_db}&user={encoded_user}&old_password=' + encodeURIComponent(oldPass) + 
              '&new_password=' + encodeURIComponent(newPass) + 
              '&confirm_password=' + encodeURIComponent(confirmPass)
    }})
    .then(function(response) {{ return response.json(); }})
    .then(function(data) {{
        if (data.success) {{
            alert('密码修改成功');
            window.location.href = '/?db={encoded_db}&user={encoded_user}&key=' + encodeURIComponent(newPass);
        }} else {{
            alert('密码修改失败: ' + data.message);
        }}
    }})
    .catch(function(error) {{
        alert('网络错误: ' + error);
    }});
}}
</script>
</head>
<body>
<div class="container">
<h1>修改密码</h1>
<div class="form-group">
<label>原密码:</label>
<input type="password" id="old_password" required>
</div>
<div class="form-group">
<label>新密码:</label>
<input type="password" id="new_password" required>
</div>
<div class="form-group">
<label>确认新密码:</label>
<input type="password" id="confirm_password" required>
</div>
<button class="btn" onclick="changePassword()">修改密码</button>
<div style="text-align:center; margin-top:15px;">
<a href="/?db={encoded_db}&user={encoded_user}&key={encoded_key}">返回表格</a>
</div>
</div>
</body>
</html>""".format(
            encoded_db=encoded_db,
            encoded_user=encoded_user,
            encoded_key=encoded_key
        )
        
        self.send_response(200)
        self.send_header('Content-type', 'text/html; charset=utf-8')
        self.end_headers()
        self.wfile.write(html.encode('utf-8'))


def get_local_ip():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(("8.8.8.8", 80))
        ip = s.getsockname()[0]
        s.close()
        return ip
    except:
        return "127.0.0.1"


def main():
    host = '0.0.0.0'
    port = 8000
    
    system = TableSystem("db")
    
    handler_class = lambda *args, **kwargs: TableRequestHandler(*args, system=system, **kwargs)
    server = HTTPServer((host, port), handler_class)
    
    local_ip = get_local_ip()
    print("=" * 50)
    print("共享填表系统启动成功!")
    print("本地访问: http://localhost:{}/".format(port))
    print("局域网访问: http://{}:{}/".format(local_ip, port))
    print("=" * 50)
    print("提示: 访问 /sync 可以手动同步数据到文件")
    print("=" * 50)
    
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        print("\n正在关闭服务器...")
        system.force_sync_all()
        server.server_close()
        print("服务器已关闭")


if __name__ == '__main__':
    main()